import express from 'express'
import cors from 'cors'
import dotenv from 'dotenv'
import OpenAI from 'openai'
import chatMemoryManager from './chatMemory.js'
import imageManager from './imageManager.js'
// 使用 Node 18+ 内置的全局 fetch；若运行环境没有，请确保 Node >= 18 或安装 node-fetch 并恢复导入。

dotenv.config()

const app = express()
app.use(cors())
app.use(express.json({ limit: '50mb' })) // 增加限制以支持图片上传
app.use(express.json({
  verify: (req, res, buf, encoding) => {
    try {
      req.rawBody = buf.toString(encoding || 'utf8')
    } catch (e) {
      req.rawBody = ''
    }
  }
}))

// 静态文件服务 - 提供上传的图片访问
app.use('/uploads', express.static('./uploads'))

// 更友好的 JSON 语法错误处理
app.use((err, req, res, next) => {
  if (err && err.type === 'entity.parse.failed') {
    console.error('JSON parse error. Raw body:', req.rawBody)
    return res.status(400).json({ error: '无效的 JSON 请求体（请确保使用 UTF-8 编码且请求体为合法 JSON）' })
  }
  next(err)
})

const PORT = process.env.PORT || 3000

// 初始化聊天记忆管理器
chatMemoryManager.initialize().catch(err => {
  console.error('初始化聊天记忆管理器失败:', err)
})

// 初始化图片管理器
imageManager.initialize().catch(err => {
  console.error('初始化图片管理器失败:', err)
})

// Helper: build prompt combining user message + concise retrieval results
function buildPrompt(message, results = [], chatOnly = false) {
  // 针对特定高风险缺陷（如雷击）使用专用精简 prompt，提高回答的准确性与可执行性
  const defectKeywords = ['雷击', '雷击损伤', '雷击孔洞', '烧蚀', '闪电']
  const msgLower = String(message || '').toLowerCase()
  const hasDefectKeywordInMessage = defectKeywords.some(k => msgLower.includes(k))
  const hasDefectKeywordInResults = (results || []).some(r => Array.isArray(r.tags) && r.tags.join(',').toLowerCase().split(',').some(t => defectKeywords.includes(t)))
  if (hasDefectKeywordInMessage || hasDefectKeywordInResults) {
    // 专用模板：结构化、可执行、包含检查/临时处置/NDT 建议与上传清单
    return `你是风力发电叶片缺陷检测系统的智能助手。用户问题：${message}\n\n检测到与“雷击/烧蚀”相关的查询或检索结果。请简明扼要地按以下结构输出（每项不要超过3行）：\n1) 紧急安全措施（若发现冒烟、贯穿或人员危险需立刻停机/隔离）；\n2) 现场拍照与记录清单（列出必须的照片视角和元数据，如带标尺的近照、全景、叶片编号、GPS、风速、运行状态）；\n3) 快速目测判定指导（用可读判断标准区分“表面烧蚀/浅表碳化”、“分层/中度损伤”、“贯穿/结构损坏”）；\n4) 推荐的无损检测方法（按优先顺序：超声、红外热像、敲击/敲音、内窥镜/X 射线等）并说明每项适用场景；\n5) 临时处置与运营建议（例如：局部覆盖、停机与否的判断要点、优先级标注）；\n6) 提示需要上传的图像与元数据字段（明确 dataUrl、bbox、拍摄角度、检测置信度等），以便系统进一步分析；\n7) 若检索到实际图片，请基于每张图片的 detections（类别与置信度）给出针对性的结论与置信度说明。\n\n严格要求：不要编造不存在的检测数据或图片细节；当信息不足时说明将无法判断并给出收集证据的明确步骤。`
  }
  // 如果是 chatOnly 模式，直接返回一个面向对话的 prompt，不使用检索结果
  if (chatOnly) {
    return `你是风力发电叶片缺陷检测系统的智能助手。用户问题：${message}\n\n请基于通用常识和工程经验简要回答，给出可执行建议或澄清问题的追问。答案要简洁、准确，不要编造与用户无关的图片信息。`
  }
  // 将检索结果格式化为简洁的条目，包含 name、tags、以及 detections 的简短描述
  const ctx = (results || []).slice(0, 6).map((r, i) => {
    const parts = []
    if (r.name) parts.push(`名称: ${r.name}`)
    if (Array.isArray(r.tags) && r.tags.length) parts.push(`标签: ${r.tags.join(', ')}`)
    if (Array.isArray(r.detections) && r.detections.length) {
      const det = r.detections.map(d => {
        const cls = d.class || d.label || d.type || '未知'
        const conf = (typeof d.confidence === 'number') ? `(${(d.confidence*100).toFixed(0)}%)` : ''
        return `${cls}${conf}`
      }).join('; ')
      parts.push(`检测: ${det}`)
    }
    if (r.url) parts.push(`URL: ${r.url}`)
    return `${i + 1}. ${parts.join(' | ')}`
  }).join('\n')

  // 如果没有检索结果，要求模型不要伪造图片信息，而是给出概率估计及可执行建议
  if (!ctx) {
    return `你是风力发电叶片缺陷检测系统的智能助手。用户问题：${message}\n\n当前没有从图片库检索到相关图片。不要捏造图片或检测信息。基于常识和工程经验，请返回：\n1) 对用户问题的简短说明（若无法确定，说明具体原因）；\n2) 列出最多3个“最可能的缺陷类型”，每项后给出简要理由和一个估计置信度（高/中/低 或 百分比），并标明这是基于常识的推断；\n3) 针对每个可能缺陷给出1-2条可执行的下一步检查或临时处置建议（例如：局部拍照、清理表面、安排近距离无损检测、停机检查等）；\n4) 推荐具体搜索关键词或示例查询，以帮助用户上传或检索更精确的图片；\n要求：答案要简洁（每项不超过2-3行），明确标注“基于推断”字样，且不要列出不存在的图片或伪造检测数值。`
  }

  // 若有检索结果，指示模型基于检测置信度给出概率估计与建议
  return `你是风力发电叶片缺陷检测系统的智能助手。使用下面的检索结果来回答用户查询：\n\n用户问题：${message}\n\n检索结果（最多6条，每行为一条摘要）：\n${ctx}\n\n请仅基于上面提供的检索结果作答：\n- 对每个重要结论（例如“裂纹”或“油污”）给出一个简短的概率估计（例如：置信度86%），说明依据（例如：检测置信度、标签匹配等），并给出简短的理由（1句）；\n- 提供明确的下一步操作建议（检查/维修/监控/拍照/取样），并指出优先级（高/中/低）；\n- 在答案末尾列出匹配的图片名称（如果有），以“图片名称：”开头；\n- 如果给出的信息不足以做出确定结论，请直接说明并给出如何收集更多证据的步骤。\n- 不要捏造不存在的图片或检测结果。`
}

app.post('/api/chat', async (req, res) => {
  try {
    const body = req.body || {}
    const message = body.message || body.prompt || ''
    const results = body.results || []
    const useMemory = body.useMemory !== false // 默认使用记忆功能
    
    console.log('POST /api/chat received body:', JSON.stringify(req.body), 'using message:', message ? 'message' : (body.prompt ? 'prompt' : 'none'))
    if (!message) return res.status(400).json({ error: 'missing message (or prompt)' })

    // 如果启用记忆功能，获取相关历史对话
    let historyContext = ''
    if (useMemory) {
      try {
        const relevantConversations = await chatMemoryManager.searchRelevantConversations(message, 3)
        if (relevantConversations.length > 0) {
          historyContext = '\n\n【相关历史对话】：\n'
          relevantConversations.forEach((conv, index) => {
            const meta = conv.metadata
            historyContext += `\n对话${index + 1}:\n用户: ${meta.userMessage}\n助手: ${meta.botResponse}\n`
          })
          historyContext += '\n请结合以上历史对话理解当前问题。\n'
          console.log('🧠 已加载历史上下文，共', relevantConversations.length, '条相关对话')
        }
      } catch (err) {
        console.error('获取历史上下文失败:', err)
      }
    }

    // 构建 prompt（包含历史上下文）
    const basePrompt = buildPrompt(message, results, body.chatOnly === true)
    const prompt = historyContext ? historyContext + '\n' + basePrompt : basePrompt

    // 如果没有检索结果且不是仅聊天模式，返回确定性的工程建议，避免模型泛化回答
    if (!body.chatOnly && (!results || results.length === 0)) {
      const staticReply = `1) 当前无图片可供分析，以下判断基于风力发电叶片常见缺陷的工程经验：\n\n2) 最可能的缺陷（按优先级）：\n- 前缘腐蚀（Leading edge erosion）\n  理由：长期暴露于风雨、沙尘导致涂层和前缘材料退化。\n  估计置信度：高（≈85%）\n- 表面裂纹（Surface cracking）\n  理由：疲劳载荷或局部应力集中引发微裂纹扩展。\n  估计置信度：中（≈70%）\n- 结构分层（Delamination）\n  理由：复合材料层间粘结失效，常由冲击或湿气侵入引起。\n  估计置信度：中（≈65%）\n\n3) 后续检查建议（按缺陷类型）：\n- 前缘腐蚀：局部高分辨率近拍（带标尺），检查叶尖与前缘涂层完整性；如确认，安排表面修复或更换前缘补片。\n- 表面裂纹：进行近距目视或无人机低空拍照，标记裂纹起点并做超声或敲击初筛；必要时安排无损检测（超声或红外）。\n- 结构分层：先做敲击/听音判断空响区，再用红外热像或超声 C 扫描确认内部分层范围。\n\n4) 推荐搜索/上传关键词："风力叶片 前缘腐蚀 图片"、"风电叶片 表面裂纹 示例"、"复合材料 分层 缺陷 对比图"。\n\n5) 建议上传的图片与元数据：近景（带标尺）、全景（定位叶片位置）、受损局部多角度、拍摄位置（叶片编号/位置）、拍摄时间与运行状态。上传后系统将基于图像给出更精确的结论和操作建议。\n\n若你希望我给出更针对性的修复步骤或打印清单，请勾选“仅聊天”并说明是否需要现场可操作的步骤。`

      const structured = {
        possibilities: [
          { name: '前缘腐蚀', reason: '长期暴露于风雨、沙尘导致涂层和前缘材料退化。', confidence: '高 (≈85%)' },
          { name: '表面裂纹', reason: '疲劳载荷或局部应力集中引发微裂纹扩展。', confidence: '中 (≈70%)' },
          { name: '结构分层', reason: '复合材料层间粘结失效，常由冲击或湿气侵入引起。', confidence: '中 (≈65%)' }
        ],
        checks: [
          { title: '前缘腐蚀检查', steps: ['局部高分辨率近拍（带标尺）', '重点检查叶尖与前缘涂层完整性'] },
          { title: '表面裂纹检查', steps: ['近距目视或无人机低空拍照', '标记裂纹起点并做超声或敲击初筛'] },
          { title: '结构分层检查', steps: ['敲击/听音判断空响区', '红外热像或超声 C 扫描确认内部分层范围'] }
        ],
        uploadChecklist: ['近景（带标尺）', '全景（定位叶片位置）', '受损局部多角度', '拍摄位置（叶片编号/位置）', '拍摄时间与运行状态'],
        searchKeywords: ['风力叶片 前缘腐蚀 图片', '风电叶片 表面裂纹 示例', '复合材料 分层 缺陷 对比图']
      }

      // 保存对话到向量数据库
      if (useMemory) {
        await chatMemoryManager.saveConversation(message, staticReply, { hasResults: false }).catch(err => {
          console.error('保存对话失败:', err)
        })
      }

      return res.json({ text: staticReply, structured, results: [] })
    }

    // Priority: if ALIYUN_API_KEY + ALIYUN_BASE_URL provided, call 阿里云兼容OpenAI接口 via official SDK
    if (process.env.ALIYUN_API_KEY && process.env.ALIYUN_BASE_URL) {
      try {
        const client = new OpenAI({ apiKey: process.env.ALIYUN_API_KEY, baseURL: process.env.ALIYUN_BASE_URL })
        const model = process.env.ALIYUN_MODEL || 'qwen-plus'
        const resp = await client.chat.completions.create({
          model,
          messages: [
            { role: 'system', content: '你是风力发电叶片缺陷检测系统的智能助手，回答需简洁并基于给定检索结果。能够记住历史对话并在回答中体现上下文连贯性。' },
            { role: 'user', content: prompt }
          ],
          max_tokens: 600,
          temperature: 0.0
        })

        console.log('阿里云 SDK response:', JSON.stringify(resp))
        const text = resp.choices?.[0]?.message?.content || resp.data?.[0]?.content || JSON.stringify(resp)
        
        // 保存对话到向量数据库
        if (useMemory) {
          await chatMemoryManager.saveConversation(message, text, { 
            provider: 'aliyun',
            hasResults: results && results.length > 0
          }).catch(err => {
            console.error('保存对话失败:', err)
          })
        }

        const resultsToReturn = (results || []).map(r => ({ id: r.id, name: r.name, dataUrl: r.dataUrl || r.url || '', tags: r.tags || [], detections: r.detections || [] }))
        return res.json({ text, results: resultsToReturn })
      } catch (e) {
        console.error('阿里云 SDK 调用失败', e)
        if (e?.response) {
          try { 
            const txt = await e.response.text()
            console.error('阿里云 SDK 响应文本:', txt)
          } catch(_) {
            // 忽略响应读取错误
          }
        }
        // 如果 SDK 调用失败，继续尝试旧的 ALIYUN_INVOKE_URL 路径或 OpenAI 回退
      }
    }

    // If ALIYUN_INVOKE_URL + ALIYUN_API_TOKEN provided (generic HTTP Bearer token), use that (backward compatible)
    if (process.env.ALIYUN_INVOKE_URL && process.env.ALIYUN_API_TOKEN) {
      const body = {
        model: process.env.ALIYUN_MODEL || 'default',
        prompt
      }

      const r = await fetch(process.env.ALIYUN_INVOKE_URL, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${process.env.ALIYUN_API_TOKEN}`
        },
        body: JSON.stringify(body)
      })

      const raw = await r.text()
      console.log('ALIYUN_INVOKE_URL response status:', r.status, 'body:', raw)
      if (!r.ok) {
        const payload = { error: `阿里云调用失败`, status: r.status }
        if (process.env.NODE_ENV === 'development') payload.debug = raw
        return res.status(502).json(payload)
      }

      let j
      try { j = JSON.parse(raw) } catch (err) { j = raw }
      const text = j.data?.content || j.choices?.[0]?.message?.content || j.result || j.text || JSON.stringify(j)
      
      // 保存对话到向量数据库
      if (useMemory) {
        await chatMemoryManager.saveConversation(message, text, { 
          provider: 'aliyun-invoke',
          hasResults: results && results.length > 0
        }).catch(err => {
          console.error('保存对话失败:', err)
        })
      }

      const resultsToReturn = (results || []).map(r => ({ id: r.id, name: r.name, dataUrl: r.dataUrl || r.url || '', tags: r.tags || [], detections: r.detections || [] }))
      return res.json({ text, results: resultsToReturn })
    }

    // Fallback: if OPENAI_KEY is set, call OpenAI from server-side
    if (process.env.OPENAI_KEY) {
      const openaiRes = await fetch('https://api.openai.com/v1/chat/completions', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${process.env.OPENAI_KEY}`
        },
        body: JSON.stringify({
          model: process.env.OPENAI_MODEL || 'gpt-3.5-turbo',
          messages: [
            { role: 'system', content: '你是风力发电叶片缺陷检测系统的智能助手，回答需简洁并基于给定检索结果。' },
            { role: 'user', content: prompt }
          ],
          max_tokens: 600,
          temperature: 0.0
        })
      })

      const openaiText = await openaiRes.text()
      console.log('OpenAI response status:', openaiRes.status, 'body:', openaiText)
      if (!openaiRes.ok) {
        const payload = { error: `OpenAI 调用失败`, status: openaiRes.status }
        if (process.env.NODE_ENV === 'development') payload.debug = openaiText
        return res.status(502).json(payload)
      }

      const j = JSON.parse(openaiText)
      const text = j.choices?.[0]?.message?.content || '未收到模型回复。'
      
      // 保存对话到向量数据库
      if (useMemory) {
        await chatMemoryManager.saveConversation(message, text, { 
          provider: 'openai',
          hasResults: results && results.length > 0
        }).catch(err => {
          console.error('保存对话失败:', err)
        })
      }

      const resultsToReturn = (results || []).map(r => ({ id: r.id, name: r.name, dataUrl: r.dataUrl || r.url || '', tags: r.tags || [], detections: r.detections || [] }))
      return res.json({ text, results: resultsToReturn })
    }

    // 如果既没有阿里云配置也没有 OpenAI key，返回一个友好提示
    const errPayload = { error: '未配置后端模型提供者。请在 server/.env 中设置 ALIYUN_API_KEY & ALIYUN_BASE_URL 或 ALIYUN_INVOKE_URL & ALIYUN_API_TOKEN 或 OPENAI_KEY。' }
    if (process.env.NODE_ENV === 'development') errPayload.debug = 'No provider env set: ' + JSON.stringify(process.env)
    return res.status(400).json(errPayload)
  } catch (err) {
    console.error('api/chat error', err)
    const payload = { error: err.message || String(err) }
    if (process.env.NODE_ENV === 'development') payload.debug = err.stack || String(err)
    return res.status(500).json(payload)
  }
})

// 新增：获取系统统计信息（包含 ChromaDB 状态）
app.get('/api/stats', async (req, res) => {
  try {
    const stats = await chatMemoryManager.getStats()
    res.json(stats)
  } catch (err) {
    console.error('获取统计信息失败', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 新增：健康检查端点（完整的服务监控）
app.get('/api/health', async (req, res) => {
  try {
    const healthStatus = {
      timestamp: new Date().toISOString(),
      services: {
        backend: {
          status: 'healthy',
          uptime: process.uptime(),
          memory: process.memoryUsage(),
          port: PORT
        },
        chromaDB: {
          status: 'unknown',
          mode: 'unknown',
          connected: false,
          reconnectAttempts: 0
        },
        aiProvider: {
          status: 'unknown',
          provider: 'none'
        }
      }
    }

    // 检查 ChromaDB 状态
    try {
      const stats = await chatMemoryManager.getStats()
      healthStatus.services.chromaDB = {
        status: stats.useChromaDB ? 'healthy' : 'degraded',
        mode: stats.mode,
        connected: stats.useChromaDB,
        reconnectAttempts: stats.reconnectAttempts,
        totalConversations: stats.totalConversations,
        autoReconnectEnabled: stats.autoReconnectEnabled
      }
    } catch (err) {
      healthStatus.services.chromaDB.status = 'error'
      healthStatus.services.chromaDB.error = err.message
    }

    // 检查 AI 提供者配置
    if (process.env.ALIYUN_API_KEY && process.env.ALIYUN_BASE_URL) {
      healthStatus.services.aiProvider = {
        status: 'configured',
        provider: 'aliyun-sdk',
        model: process.env.ALIYUN_MODEL || 'qwen-plus'
      }
    } else if (process.env.ALIYUN_INVOKE_URL && process.env.ALIYUN_API_TOKEN) {
      healthStatus.services.aiProvider = {
        status: 'configured',
        provider: 'aliyun-invoke',
        model: process.env.ALIYUN_MODEL || 'default'
      }
    } else if (process.env.OPENAI_KEY) {
      healthStatus.services.aiProvider = {
        status: 'configured',
        provider: 'openai',
        model: process.env.OPENAI_MODEL || 'gpt-3.5-turbo'
      }
    } else {
      healthStatus.services.aiProvider = {
        status: 'not_configured',
        provider: 'none'
      }
    }

    // 整体健康状态判断
    const isHealthy = 
      healthStatus.services.backend.status === 'healthy' &&
      healthStatus.services.aiProvider.status === 'configured'

    res.status(isHealthy ? 200 : 503).json({
      ...healthStatus,
      overall: isHealthy ? 'healthy' : 'degraded'
    })
  } catch (err) {
    console.error('健康检查失败', err)
    res.status(500).json({ 
      overall: 'error',
      error: err.message || String(err) 
    })
  }
})

// 新增：获取聊天历史记录（支持分页和日期筛选）
app.get('/api/chat/history', async (req, res) => {
  try {
    const limit = parseInt(req.query.limit) || 20
    const page = parseInt(req.query.page) || 1
    const dateFilter = req.query.dateFilter || 'all'
    
    const result = await chatMemoryManager.getRecentConversations(limit, page, dateFilter)
    res.json(result)
  } catch (err) {
    console.error('获取聊天历史失败', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 新增：搜索相关对话
app.post('/api/chat/search', async (req, res) => {
  try {
    const { query, limit = 10 } = req.body
    if (!query) {
      return res.status(400).json({ error: '缺少查询参数' })
    }
    const conversations = await chatMemoryManager.searchRelevantConversations(query, limit)
    res.json({ conversations })
  } catch (err) {
    console.error('搜索对话失败', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 新增：删除指定对话
app.delete('/api/chat/history/:id', async (req, res) => {
  try {
    const { id } = req.params
    const success = await chatMemoryManager.deleteConversation(id)
    res.json({ success })
  } catch (err) {
    console.error('删除对话失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 新增：清空所有对话历史
app.delete('/api/chat/history', async (req, res) => {
  try {
    const success = await chatMemoryManager.clearAllConversations()
    res.json({ success })
  } catch (err) {
    console.error('清空对话历史失败', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// ========== 数据管理 API ==========

// 模拟 AI 缺陷检测
function mockAIDetection(_imageName) {
  const defectTypes = ['裂纹', '腐蚀', '油污', '磨损', '分层']
  const numDetections = Math.floor(Math.random() * 3) + 1
  const detections = []
  
  for (let i = 0; i < numDetections; i++) {
    detections.push({
      class: defectTypes[Math.floor(Math.random() * defectTypes.length)],
      confidence: 0.6 + Math.random() * 0.35,
      bbox: [
        Math.floor(Math.random() * 100),
        Math.floor(Math.random() * 100),
        Math.floor(Math.random() * 200) + 100,
        Math.floor(Math.random() * 200) + 100
      ]
    })
  }
  
  return detections
}

// 生成 AI 描述
function generateAIDescription(detections) {
  if (!detections || detections.length === 0) {
    return '叶片表面状态正常，未检测到明显缺陷。'
  }
  
  const defectList = detections.map(d => d.class).join('、')
  const maxConf = Math.max(...detections.map(d => d.confidence))
  const severity = maxConf > 0.85 ? '严重' : maxConf > 0.7 ? '中度' : '轻微'
  
  return `检测到叶片表面存在${defectList}等缺陷，缺陷程度为${severity}。建议进行进一步检查和维护。`
}

// ========== 聊天功能需要的图片接口（兼容旧版 API） ==========

// 列出所有图片 - 聊天功能使用
app.get('/api/images', async (req, res) => {
  try {
    const images = await imageManager.listImages()
    res.json(images) // 直接返回数组，不包装在 data 字段中
  } catch (err) {
    console.error('获取图片列表失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 搜索图片 - 聊天功能使用
app.get('/api/images/search', async (req, res) => {
  try {
    const { q = '', tag = '', dateRange = 'all', sortBy = 'createdAt' } = req.query
    
    const results = await imageManager.searchImages({
      query: q,
      tag,
      dateRange,
      sortBy
    })
    
    res.json(results) // 直接返回数组，不包装在 data 字段中
  } catch (err) {
    console.error('搜索图片失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 删除图片 - 聊天功能使用
app.delete('/api/images/:id', async (req, res) => {
  try {
    const { id } = req.params
    await imageManager.deleteImage(id)
    
    res.json({
      ok: true,
      message: '图片已删除'
    })
  } catch (err) {
    console.error('删除图片失败:', err)
    res.json({
      ok: false,
      reason: err.message || String(err)
    })
  }
})

// 更新图片 - 聊天功能使用
app.patch('/api/images/:id', async (req, res) => {
  try {
    const { id } = req.params
    const updates = req.body
    
    const result = await imageManager.updateImage(id, updates)
    
    res.json(result)
  } catch (err) {
    console.error('更新图片失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 检测并保存图片 - 聊天功能使用
app.post('/api/detect', async (req, res) => {
  try {
    const { name, dataUrl } = req.body
    
    if (!name || !dataUrl) {
      return res.status(400).json({ error: '缺少必要参数：name 或 dataUrl' })
    }
    
    let detections = []
    let tags = []
    let description = ''
    
    // 默认启用 AI 检测
    console.log('🤖 正在进行 AI 检测...')
    detections = mockAIDetection(name)
    tags = [...new Set(detections.map(d => d.class))]
    description = generateAIDescription(detections)
    console.log(`✅ AI 检测完成：检测到 ${detections.length} 个缺陷`)
    
    // 保存图片
    const result = await imageManager.saveImage({
      name,
      base64Data: dataUrl,
      tags,
      description,
      detections,
      aiProcessed: true
    })
    
    res.json(result)
  } catch (err) {
    console.error('检测并保存图片失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// ========== 数据管理页面使用的 API（新版，返回格式包含 success 和 data） ==========

// 上传图片（支持 AI 检测）
app.post('/api/data/upload', async (req, res) => {
  try {
    const { name, dataUrl, aiEnabled = false } = req.body
    
    if (!name || !dataUrl) {
      return res.status(400).json({ error: '缺少必要参数：name 或 dataUrl' })
    }
    
    let detections = []
    let tags = []
    let description = ''
    
    // 如果启用 AI，进行检测
    if (aiEnabled) {
      console.log('🤖 正在进行 AI 检测...')
      
      // TODO: 这里可以调用真实的 AI 模型进行检测
      // 目前使用模拟数据
      detections = mockAIDetection(name)
      tags = [...new Set(detections.map(d => d.class))]
      description = generateAIDescription(detections)
      
      console.log(`✅ AI 检测完成：检测到 ${detections.length} 个缺陷`)
    }
    
    // 保存图片
    const result = await imageManager.saveImage({
      name,
      base64Data: dataUrl,
      tags,
      description,
      detections,
      aiProcessed: aiEnabled
    })
    
    res.json({
      success: true,
      data: result
    })
  } catch (err) {
    console.error('上传图片失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 批量上传
app.post('/api/data/upload-batch', async (req, res) => {
  try {
    const { images, aiEnabled = false } = req.body
    
    if (!images || !Array.isArray(images)) {
      return res.status(400).json({ error: '缺少 images 数组' })
    }
    
    const results = []
    
    for (const img of images) {
      try {
        let detections = []
        let tags = []
        let description = ''
        
        if (aiEnabled) {
          detections = mockAIDetection(img.name)
          tags = [...new Set(detections.map(d => d.class))]
          description = generateAIDescription(detections)
        }
        
        const result = await imageManager.saveImage({
          name: img.name,
          base64Data: img.dataUrl,
          tags,
          description,
          detections,
          aiProcessed: aiEnabled
        })
        
        results.push({ success: true, data: result })
      } catch (err) {
        results.push({ success: false, error: err.message, name: img.name })
      }
    }
    
    res.json({
      success: true,
      results
    })
  } catch (err) {
    console.error('批量上传失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 列出所有图片
app.get('/api/data/images', async (req, res) => {
  try {
    const images = await imageManager.listImages()
    res.json({
      success: true,
      data: images
    })
  } catch (err) {
    console.error('获取图片列表失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 搜索图片
app.post('/api/data/search', async (req, res) => {
  try {
    const { query = '', tag = '', dateRange = 'all', sortBy = 'createdAt' } = req.body
    
    const results = await imageManager.searchImages({
      query,
      tag,
      dateRange,
      sortBy
    })
    
    res.json({
      success: true,
      data: results
    })
  } catch (err) {
    console.error('搜索图片失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 相似图片搜索
app.post('/api/data/similar', async (req, res) => {
  try {
    const { imageId, limit = 5 } = req.body
    
    if (!imageId) {
      return res.status(400).json({ error: '缺少 imageId 参数' })
    }
    
    const results = await imageManager.searchSimilarImages(imageId, limit)
    
    res.json({
      success: true,
      data: results
    })
  } catch (err) {
    console.error('相似图片搜索失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 获取图片详情
app.get('/api/data/images/:id', async (req, res) => {
  try {
    const { id } = req.params
    const image = await imageManager.getImage(id)
    
    if (!image) {
      return res.status(404).json({ error: '图片不存在' })
    }
    
    res.json({
      success: true,
      data: image
    })
  } catch (err) {
    console.error('获取图片详情失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 删除图片
app.delete('/api/data/images/:id', async (req, res) => {
  try {
    const { id } = req.params
    await imageManager.deleteImage(id)
    
    res.json({
      success: true,
      message: '图片已删除'
    })
  } catch (err) {
    console.error('删除图片失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 批量删除图片
app.post('/api/data/delete-batch', async (req, res) => {
  try {
    const { imageIds } = req.body
    
    if (!imageIds || !Array.isArray(imageIds)) {
      return res.status(400).json({ error: '缺少 imageIds 数组' })
    }
    
    const results = []
    
    for (const id of imageIds) {
      try {
        await imageManager.deleteImage(id)
        results.push({ success: true, id })
      } catch (err) {
        results.push({ success: false, id, error: err.message })
      }
    }
    
    res.json({
      success: true,
      results
    })
  } catch (err) {
    console.error('批量删除失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 获取统计信息
app.get('/api/data/statistics', async (req, res) => {
  try {
    const stats = await imageManager.getStatistics()
    
    res.json({
      success: true,
      data: stats
    })
  } catch (err) {
    console.error('获取统计信息失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

// 更新图片元数据
app.put('/api/data/images/:id', async (req, res) => {
  try {
    const { id } = req.params
    const updates = req.body
    
    const result = await imageManager.updateImage(id, updates)
    
    res.json({
      success: true,
      data: result
    })
  } catch (err) {
    console.error('更新图片失败:', err)
    res.status(500).json({ error: err.message || String(err) })
  }
})

app.listen(PORT, () => {
  console.log(`Backend proxy listening on port ${PORT}`)
  console.log('ENV sample: set ALIYUN_API_KEY & ALIYUN_BASE_URL OR ALIYUN_INVOKE_URL & ALIYUN_API_TOKEN OR OPENAI_KEY in server/.env')
})